package com.hzwl.core

import com.hzwl.core.Flag.flag
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.*
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.http.MediaType
import org.springframework.scheduling.annotation.Async
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import java.io.BufferedReader
import java.io.File
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.*

/**
 * TODO
 * @author lin
 */
@Service
class RunService{

    @Value("\${exe.path}")
    lateinit var exePath: String

    @Value("\${out.path}")
    lateinit var outPath: String

    @Async
    fun generate(speed: String) {
        saveHydrodynamics(speed)
        val workingDir = File(exePath).parentFile

        // 生成初始速度文件
        val INITIALU1 = "${workingDir.parentFile}/INITIALU1.DAT"
        val file = File(INITIALU1)
        if (file.exists()) {
            file.delete()
        }
        val lines = mutableListOf<String>()
        lines.add("u1")
        repeat(3808) {
            lines.add(speed)
        }

        File(INITIALU1).writeText(lines.joinToString("\n") + "\n")

        val INITIALV1 = "${workingDir.parentFile}/INITIALV1.DAT"
        val file1 = File(INITIALV1)
        if (file1.exists()) {
            file1.delete()
        }
        val lines1 = mutableListOf<String>()
        lines1.add("v1")
        repeat(3808) {
            lines1.add(speed)
        }
        File(INITIALV1).writeText(lines1.joinToString("\n") + "\n")

        // 执行程序
        val process = ProcessBuilder(exePath)
            .directory(workingDir)
            .start()

        val outReader = BufferedReader(InputStreamReader(process.inputStream))
        val errReader = BufferedReader(InputStreamReader(process.errorStream))

        // 读取输出
        outReader.useLines { lines -> lines.forEach { println(it) } }
        errReader.useLines { lines -> lines.forEach { println("Error: $it") } }

        // 获取并处理退出值
        val exitCode = process.waitFor()
        if (exitCode == 0) {
            println("Program executed successfully.")
        } else {
            println("Program exited with error code: $exitCode")
        }
        generateJsonAndUpload(speed)
        flag = false
    }

    /**
     * 保存生成结果
     *
     * @param speed 流速
     */
    fun saveHydrodynamics(speed: String) {
        val restTemplate = RestTemplate()
        val url = "http://39.107.140.142:9215/hydrodynamics"  // 替换为你的实际URL

        val headers = HttpHeaders().apply {
            contentType = MediaType.APPLICATION_JSON
        }

        val now = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())

        val hydrodynamicsMap = HashMap<String, Any>().apply {
            put("speed", speed.toDouble())
            put("generateStartTime", now)
            put("status", 0)  // 替换为实际的状态值
        }

        val request = HttpEntity(hydrodynamicsMap, headers)
        val response = restTemplate.postForEntity(url, request, Any::class.java)
        if (response.statusCode.is2xxSuccessful) {
            println("Hydrodynamics saved successfully with ID: ${response.body}")
        } else {
            println("Failed to save Hydrodynamics: ${response.statusCode}")
        }
    }

    /**
     * 上传生成结果
     *
     * @param speed
     * @param fileList
     */
    fun updateHydrodynamics(speed: String, fileList: List<String>) {
        val restTemplate = RestTemplate()
        val url = "http://39.107.140.142:9215/hydrodynamics"  // 替换为你的实际URL

        val headers = HttpHeaders().apply {
            contentType = MediaType.APPLICATION_JSON
        }

        val now = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())

        val hydrodynamicsMap = HashMap<String, Any>().apply {
            put("speed", speed.toDouble())
            put("generateEndTime", now)
            put("fileList", fileList)
            put("status", 1)  // 替换为实际的状态值
        }

        val request = HttpEntity(hydrodynamicsMap, headers)
        restTemplate.put(url, request)
    }

    fun generateJsonAndUpload(speed: String) {
        val workingDir = File(exePath).parentFile.parentFile
        val ZUV = "$workingDir/OUTPUT/ZUV.OUT" // 替换成你的文件路径


        val json = mutableListOf<ZuvData>()
        var currentJsonMap: ZuvData = ZuvData()

        File(ZUV).forEachLine { line ->
            when {
                line.trim().startsWith("JT=") -> {
                    currentJsonMap = ZuvData()
                    json.add(currentJsonMap)
                    resetFlags()
                }
                line.trim().startsWith("Z2=") -> resetFlags(z2 = true)
                line.trim().startsWith("W2=") -> resetFlags(w2 = true)
                line.trim().startsWith("FI=") -> resetFlags(fi = true)
                z2StartReading -> readValues(line, currentJsonMap.z2)
                w2StartReading -> readValues(line, currentJsonMap.w2)
                fiStartReading -> readValues(line, currentJsonMap.fi)
            }
        }

        val H2U2V2 = "$workingDir/OUTPUT/H2U2V2.OUT"

        var index = -1
        File(H2U2V2).forEachLine { line ->
            when {
                line.trim().startsWith("JT=") -> {
                    index++
                    resetFlags()
                }
                line.trim().startsWith("H2=") -> resetFlags(h2 = true)

                line.trim().startsWith("U2=") -> resetFlags(u2 = true)

                line.trim().startsWith("V2=") -> resetFlags(v2 = true)

                h2StartReading -> readValues(line, json[index].h2)
                u2StartReading -> readValues(line, json[index].u2)
                v2StartReading -> readValues(line, json[index].v2)

            }
        }
        json.forEach(ZuvData::setColor)
        val templateFile = File("$workingDir/template.geojson")
        val templateContent = templateFile.readText(Charsets.UTF_8)
        val template = Json.parseToJsonElement(templateContent).jsonObject
        val zuvDataList = evenlySample(json, 48)
        val fileList = mutableListOf<String>()
        zuvDataList.forEachIndexed { idx, zuvData ->
            // 复制 template
            val templateCopy = template.toMutableMap()

            val updatedFeatures = templateCopy["features"]?.jsonArray?.mapIndexed { index, feature ->
                val propertiesObject = feature.jsonObject["properties"]?.jsonObject?.toMutableMap() ?: mutableMapOf()
                propertiesObject["水位"] = JsonPrimitive(zuvData.z2.getOrElse(index) { "" }.toString() + "m")
                propertiesObject["合成流速"] = JsonPrimitive(zuvData.w2.getOrElse(index) { "" }.toString() + "m/s")
                propertiesObject["流向"] = JsonPrimitive(zuvData.fi.getOrElse(index) { "" }.toString())
                propertiesObject["水深"] = JsonPrimitive(zuvData.h2.getOrElse(index) { "" }.toString() + "m")
                propertiesObject["流速U"] = JsonPrimitive(zuvData.u2.getOrElse(index) { "" }.toString() + "m/s")
                propertiesObject["流速V"] = JsonPrimitive(zuvData.v2.getOrElse(index) { "" }.toString() + "m/s")
                propertiesObject["color"] = JsonPrimitive(zuvData.color.getOrElse(index) { "" }.toString())
                try {
                    propertiesObject.remove("Nodes")
                    propertiesObject.remove("NO")
                    propertiesObject.remove("I")
                    propertiesObject.remove("J")
                    propertiesObject.remove("Elevation")
                } catch (_: Exception) {
                }
                val updatedFeature = feature.jsonObject.toMutableMap()
                updatedFeature["properties"] = JsonObject(propertiesObject)

                JsonObject(updatedFeature)
            }

            // 更新模板中的 features
            templateCopy["features"] = JsonArray(updatedFeatures!!)

            // 将更新后的模板保存为新的文件
            val tempFile: File
            val updatedTemplateJson = JsonObject(templateCopy)

            val filePath = "$outPath/$speed---$idx.geojson"
            File(filePath).writeText(Json.encodeToString(updatedTemplateJson))
            fileList.add(filePath)

        }
        updateHydrodynamics(speed, fileList)
    }

}

fun <T> evenlySample(array: MutableList<T>, count: Int): List<T> {
    if (count > array.size) {
        return array.toList()
    }
    val step = array.size.toDouble() / count

    return List(count) { i -> array[(i * step).toInt()] }

}
